package com.swak.boot.config.monitor;

import static com.swak.boot.Application.APP_LOGGER;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.RegistryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.swak.monitor.dubbo.exception.ConfigurationException;
import com.swak.monitor.dubbo.registry.config.GovernanceConfiguration;
import com.swak.monitor.dubbo.registry.config.impl.ZookeeperConfiguration;
import com.swak.monitor.dubbo.registry.metadata.MetaDataCollector;
import com.swak.monitor.dubbo.registry.metadata.impl.ZookeeperMetaDataCollector;
import com.swak.monitor.dubbo.utils.Constants;
import com.swak.utils.StringUtils;

/**
 * 加载 Dubbo 组件
 * 
 * @author lifeng
 * @date 2021/04/14
 */
@Configuration
@ComponentScan(value = { "com.swak.monitor.dubbo" })
@ConditionalOnClass({ DubboBootstrap.class })
@EnableConfigurationProperties(MonitorProperties.class)
public class AutoConfigurationDubboMonitorComponents {

	@Autowired
	MonitorProperties properties;
	URL registryUrl = null;

	public AutoConfigurationDubboMonitorComponents() {
		APP_LOGGER.debug("Loading Dubbo Monitor");
	}

	@Bean
	public GovernanceConfiguration governanceConfiguration() {
		GovernanceConfiguration dynamicConfiguration = null;
		if (StringUtils.isNotEmpty(properties.getDubbo().getRegistryAddress())) {
			registryUrl = formUrl(properties.getDubbo().getRegistryAddress(), properties.getDubbo().getRegistryGroup(),
					properties.getDubbo().getRegistryNameSpace(), properties.getDubbo().getUsername(),
					properties.getDubbo().getPassword(), properties.getDubbo().getRegistryTimeout());
		}
		dynamicConfiguration = new ZookeeperConfiguration();
		dynamicConfiguration.setUrl(registryUrl);
		return dynamicConfiguration;
	}

	@Bean
	@DependsOn("governanceConfiguration")
	public MetaDataCollector metaDataCollector() {
		MetaDataCollector metaDataCollector = null;
		metaDataCollector = new ZookeeperMetaDataCollector();
		metaDataCollector.setUrl(registryUrl);
		return metaDataCollector;
	}

	@Bean
	@DependsOn("governanceConfiguration")
	public Registry dubboRegistry() {
		Registry registry = null;
		if (registryUrl == null) {
			if (StringUtils.isBlank(properties.getDubbo().getRegistryAddress())) {
				throw new ConfigurationException(
						"Either config center or registry address is needed, please refer to https://github.com/apache/incubator-dubbo-admin/wiki/Dubbo-Admin-configuration");
			}
			registryUrl = formUrl(properties.getDubbo().getRegistryAddress(), properties.getDubbo().getRegistryGroup(),
					properties.getDubbo().getRegistryNameSpace(), properties.getDubbo().getUsername(),
					properties.getDubbo().getPassword(), properties.getDubbo().getRegistryTimeout());
		}
		RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class)
				.getAdaptiveExtension();
		registry = registryFactory.getRegistry(registryUrl);
		return registry;
	}

	private URL formUrl(String config, String group, String nameSpace, String username, String password,
			Integer timeout) {
		URL url = URL.valueOf(config);
		if (StringUtils.isNotEmpty(group)) {
			url = url.addParameter(Constants.GROUP_KEY, group);
		}
		if (StringUtils.isNotEmpty(nameSpace)) {
			url = url.addParameter(Constants.NAMESPACE_KEY, nameSpace);
		}
		if (StringUtils.isNotEmpty(username)) {
			url = url.setUsername(username);
		}
		if (StringUtils.isNotEmpty(password)) {
			url = url.setPassword(password);
		}
		if (timeout != null) {
			url = url.addParameter(Constants.TIMEOUT_KEY, timeout);
		}
		return url;
	}
}